package com.project2.myjunit.framework;

import com.project2.myjunit.annotions.*;
import org.apache.log4j.Logger;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 读取单元测试类， 以反射方式获取这个测试类中的所有方法，区分注解,
 * 以对应的顺序来调用即可.
 */
public class MyJunitRunner {

    private static Logger log= Logger.getLogger(   MyJunitRunner.class.getName() );

    public static void run(  Class cls ){
        //反射执行
        List<Method> beforeClassMethods=new ArrayList<>();  // @MyBeforeClass
        List<Method> beforeMethods=new ArrayList<>();       //@MyBefore
        List<Method> afterClassMethods=new ArrayList<>();    //@MyAfterClass
        List<Method> aftersMethods=new ArrayList<>();        //@MyAfter
        List<Method> ignoreMethods=new ArrayList<>();        //@MyIgnore
        List<Method> testMethods=new ArrayList<>();         //@MyTest

        //1. 取出cls中的方法
        Method[] ms=cls.getMethods();
        for(  Method m: ms){
            Annotation[] ans= m.getDeclaredAnnotations();    //取出这个方法上所有的注解
            for(   Annotation an:ans){
                log.debug("当前方法为:"+m.getName()+",方法上的注解:"+ an.toString());
                if(  an instanceof MyBeforeClass ){
                    beforeClassMethods.add(m);
                }else if( an instanceof MyBefore){
                    beforeMethods.add(m);
                }else if( an instanceof MyAfterClass){
                    afterClassMethods.add(m);
                }else if( an instanceof MyAfter){
                    aftersMethods.add(m);
                }else if( an instanceof MyIgnore){
                    ignoreMethods.add(m);
                }else if( an instanceof MyTest){
                    testMethods.add(m);
                }
            }
        }
        try {
            //以上完成了单元测试类的解析.
            //按生命周期顺序调用
            //1. 调用@MyBeforeClass
            for (Method m : beforeClassMethods) {
                m.invoke(null);
            }

            //循环所有的@Test的方法
            for( Method testMethod: testMethods){
                //@构造
                Object obj=cls.newInstance();
                //before
                for(Method beforeMethod: beforeMethods){
                    beforeMethod.invoke(obj);
                }
                //test
                testMethod.invoke(obj);

                //after
                for(Method afterMethod: aftersMethods){
                    afterMethod.invoke(obj);
                }
            }

            for (Method m : afterClassMethods) {
                m.invoke(null);
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}
